// prodcons++.cc
//	C++ version of producer and consumer problem using a ring buffer.
//
//	Create N_PROD producer threads and N_CONS consumer thread. 
//	Producer and consumer threads are communicating via a shared
//      ring buffer object. The operations on the shared ring buffer
//      are synchronized with semaphores.
//	
//      
// Copyright (c) 1995 The Regents of the University of Southern Queensland.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include <stdio.h>
#include "copyright.h"
#include "system.h"


#include <fcntl.h>
#include "synch.h"
#include "ring.h"

#define BUFF_SIZE 3  // the size of the round buffer
#define N_PROD    2  // the number of producers 
#define N_CONS    2  // the number of consumers
#define N_MESSG   4  // the number of messages produced by each producer
#define MAX_NAME  16 // the maximum lengh of a name

#define MAXLEN	48 
#define LINELEN	24


Thread *producers[N_PROD]; //array of pointers to the producer
Thread *consumers[N_CONS];  // and consumer threads;

char prod_names[N_PROD][MAX_NAME];  //array of charater string for prod names
char cons_names[N_CONS][MAX_NAME];  //array of charater string for cons names

Semaphore *nempty, *nfull; //two semaphores for empty and full slots
Semaphore *mutex;          //semaphore for the mutual exclusion
    
Ring *ring;



//----------------------------------------------------------------------
// Producer
// 	Loop N_MESSG times and produce a message and put it in the 
//      shared ring buffer each time.
//	"which" is simply a number identifying the producer thread.
//      
//----------------------------------------------------------------------

void
Producer(_int which)
{
    int num;
slot *message = new slot(0,0);
//建立slot实例，此信息message将被放到ring buffer里。每个信息message有一个id和一个value。
//每个生产者产生的商品的个数必须使用N_MESSG限定，否则程序没有结束
    for (num = 0; num < N_MESSG ; num++) {
       message->thread_id=which;       //producer的id
       message->value=num;             //产生的message的编号
      nempty->P();
      mutex->P();
      ring->Put(message);
      mutex->V();
      nfull->V();
    }
}

//----------------------------------------------------------------------
// Consumer
// 	endless loop to fetch messages from the ring buffer and 
//      record these message in the corresponding file.
//      
//----------------------------------------------------------------------

void
Consumer(_int which)
{
	    char str[MAXLEN];
    char fname[LINELEN];
    int fd;
    slot *message = new slot(0,0);
    // to form a output file name for this consumer thread.
    // all the messages received by this consumer will be recorded in 
    // this file.
    sprintf(fname, "tmp_%d", which);
    // create a file. Note that this is a UNIX system call.
    if ( (fd = creat(fname, 0600) ) == -1) 
    {
    perror("creat: file create failed");
    Exit(1);
    }
   
//不需要规定每个消费者消费的商品的个数
    for (; ; ) {
       nfull->P();
       mutex->P();
      ring->Get(message);
      mutex->V();
      nempty->V();
      // form a string to record the message
      sprintf(str,"producer id --> %d; Message number --> %d;\n", 
       message->thread_id,
       message->value);
      // write this string into the output file of this consumer. 
      // note that this is another UNIX system call.
      if ( write(fd, str, strlen(str)) == -1 ) {
        perror("write: write failed");
        Exit(1);
      }
    }

}



//----------------------------------------------------------------------
// ProdCons
// 	Set up semaphores for shared round buffer and 
//	create and fork producers and consumer threads
//----------------------------------------------------------------------

void
ProdCons()
{
	int i;

//建立信号量
	mutex = new Semaphore("mutux",1);
	nfull = new Semaphore("full",0);
  nempty = new Semaphore("empty",BUFF_SIZE);
    
  // 建立ring buffer，大小为BUFF_SIZE
  ring = new Ring(BUFF_SIZE);   

  // 建立并唤醒 N_PROD个生产者线程 
  for (i=0; i < N_PROD; i++) 
  {
    sprintf(prod_names[i], "producer_%d", i);

		//使用prod_names[i]创建线程
    producers[i] = new Thread(prod_names[i]); 

		//行为为Producer定义，i为Producer参数
    producers[i] -> Fork(Producer,i); 
  };
  // 建立并唤醒N_CONS 个消费者线程
  for (i=0; i < N_CONS; i++)
  {
    sprintf(cons_names[i], "consumer_%d", i);
		//使用cons_names[i]创建线程
    consumers[i] = new Thread(cons_names[i]);
		//定义行为为Consumer，i为Consumer参数
    consumers[i] -> Fork(Consumer,i); 
    };
}
